package cn.isjinhao.crws.sql.lexical.scan;

import cn.isjinhao.crws.sql.grammar.ParseException;
import cn.isjinhao.crws.sql.lexical.Sequence;
import cn.isjinhao.crws.sql.lexical.token.Token;
import cn.isjinhao.crws.sql.lexical.token.TokenType;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author ISJINHAO
 * @Date 2021/2/23 15:35
 */
public class TokenSequence extends Sequence<List<Token>, Token> {

    public TokenSequence() {
        super(new ArrayList<>(), new Token(TokenType.EOF, null));
    }

    public List<Token> getSource() {
        return source;
    }

    public void addItem(Token token) {
        source.add(token);
        length++;
    }

    @Override
    protected int length() {
        return source.size();
    }

    @Override
    protected boolean equalSequenceItem(Token c1, Token c2) {
        return c1.getType() == c2.getType();
    }

    @Override
    protected Token indexOf(int index) {
        return source.get(index);
    }

    public Token consume(TokenType type, String message) {
        if (curEqual(type)) {
            advance();
            return takeCur();
        }
        throw new ParseException(message, this);
    }

    public Token consume(String message, TokenType ...types) {
        for(TokenType type : types) {
            if (curEqual(type)) {
                advance();
                return takeCur();
            }
        }
        throw new ParseException(message, this);
    }

    public boolean curEqual(TokenType... types) {
        for (TokenType type : types) {
            if (curEqual(wrapTokenType(type))) {
                return true;
            }
        }
        return false;
    }

    public boolean nextEqual(TokenType... types) {
        for (TokenType type : types) {
            if (nextEqual(wrapTokenType(type))) {
                return true;
            }
        }
        return false;
    }

    private Token wrapTokenType(TokenType tokenType) {
        return new Token(tokenType);
    }

    public boolean equalThenAdvance(TokenType... types) {
        for (TokenType type : types) {
            if (equalThenAdvance(wrapTokenType(type))) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return source.stream().filter(token -> token.getLiteral() != null).map(item -> item.getLiteral().toString()).collect(Collectors.joining(" "));
    }
}